#include "TypeLoader.h"
#include <freetype/freetype.h>
#include <stdexcept>
#include <SERender/Resourses/Loader/TextureLoader.h>
#include <SERender/Resourses/Loader/VertexArrayLoader.h>

namespace SEngine {

    TTypesLoader::TTypesLoader()
    {
        FT_Init_FreeType(&m_library);
    }

    TTypesLoader::~TTypesLoader()
    {
        FT_Done_Face(m_face);
        FT_Done_FreeType(m_library);
    }

    TTypesLoader &TTypesLoader::SetFontTTF(Font & font)
    {
        if (m_face) {
            FT_Done_Face(m_face);
        }
        FT_Error err;
        err = FT_New_Face(m_library, font.filePath.c_str(), 0, &m_face);
        if (err) {
            throw std::runtime_error(FT_Error_String(err));
        }
        return *this;
    }

    TTypesLoader &TTypesLoader::SetPixelSize(uint32_t width, uint32_t height)
    {
        FT_Error err;
        err = FT_Set_Pixel_Sizes(m_face, width, height);
        if (err) {
            throw std::runtime_error(FT_Error_String(err));
        }
        return *this;
    }

    void TTypesLoader::LoadChar(char ch)
    {
        FT_Error err;
        err = FT_Load_Char(m_face, ch, FT_LOAD_RENDER);
        if (err) {
            throw std::runtime_error(FT_Error_String(err));
        }
    }

    std::unique_ptr<Texture> TTypesLoader::CreateTypeTexture()
    {
        if (!m_face) {
            throw std::runtime_error("Face is not create");
        }
        CurrentDrive().EnableByteAlignment(false);
        TextureLoader<Texture2D> loader;
        loader.SetInternalFormat(RED);
        loader.SetFormat(RED);
        loader.SetType(UNSIGNED_BYTE);
        loader.SetParameter(TEXTURE_MAG_FILTER, LINEAR);
        loader.SetParameter(TEXTURE_MIN_FILTER, LINEAR);
        loader.SetParameter(TEXTURE_WRAP_S, CLAMP_TO_EDGE);
        loader.SetParameter(TEXTURE_WRAP_T, CLAMP_TO_EDGE);
        auto tex = loader.CreateTexture(m_face->glyph->bitmap.width, m_face->glyph->bitmap.rows, m_face->glyph->bitmap.buffer);
        CurrentDrive().EnableByteAlignment(true);
        return tex;
    }

    std::unique_ptr<Mesh> TTypesLoader::CreateTypeMesh()
    {
        if (!m_face) {
            throw std::runtime_error("Face is not create");
        }
        VertexArrayLoader<3, 2> loader(std::make_unique<CurrentDrive>());
        float width = (float)m_face->glyph->bitmap.width;
        float height = (float)m_face->glyph->bitmap.rows;
        float bearingX = (float)m_face->glyph->bitmap_left;
        float bearingY = (float)m_face->glyph->bitmap_top;
        loader.PushVertex({bearingX, bearingY - height, 0.0f, 0.0f, 1.0f});
        loader.PushVertex({width + bearingX, bearingY - height, 0.0f, 1.0f, 1.0f});
        loader.PushVertex({width + bearingX, bearingY, 0.0f, 1.0f, 0.0f});
        loader.PushVertex({bearingX, bearingY, 0.0f, 0.0f, 0.0f});
        loader.PushFace({0, 1, 2});
        loader.PushFace({0, 2, 3});
        return std::make_unique<Mesh>(loader.CreateVertexArray());
    }
}